/* ================================================================================
//	Crypteviant!
//	Providing tough encrypted P2P Chat
//	Copyright (C) 2010  Martin Pfeifer, Tobias Rausch
//
//	This program is free software: you can redistribute it and/or modify
//	it under the terms of the GNU General Public License as published by
//	the Free Software Foundation, either version 3 of the License, or
//	(at your option) any later version.
//
//	This program is distributed in the hope that it will be useful,
//	but WITHOUT ANY WARRANTY; without even the implied warranty of
//	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//	GNU General Public License for more details.
//
//	You should have received a copy of the GNU General Public License
//	along with this program.  If not, see <http://www.gnu.org/licenses/>.
// ============================================================================== */

#ifndef ABSTRACTTIMER_HPP
#define ABSTRACTTIMER_HPP

#include <QtCore/QObject>


namespace Timer {

    /**
     * @brief Abstract Timer interface
     * @details Inherits QObject
     *
     * @class AbstractTimer abstracttimer.hpp "abstracttimer.hpp"
    */
    class AbstractTimer : public QObject
    {
        Q_OBJECT
    public:
        /**
         * @enum TimerState
         * @details NONE the Timer has not been initialized yet \n
         * INITIAL marks the initial state of the Timer. It is created and has set the m_startTime to its creation time \n
         * STARTED says that you manually started the Timer through calling @ref AbstractTimer::start() \n
         * STOPPED is set if the Timer has stopped after a @ref AbstractTimer::stop() call \n
         * TIMES_EQUAL represents the state of the Timer when it has been stopped and m_startTime and m_stopTime are equal \n
        */
        enum TimerState { NONE, INITIAL, STARTED, STOPPED, TIMES_EQUAL };

    public:
        /**
         * @brief Default Constructor
         *
         * @fn AbstractTimer(QObject*)
         * @param parent
        */
        explicit AbstractTimer(QObject *parent = 0);

        /**
         * @brief Get the start time of the Timer
         * @details Returns 0 if the Timer hasnt been started
         *
         * @fn getStartTime() const
         * @return unsigned long
        */
        virtual unsigned long getStartTime() const;

        /**
         * @brief Get the stop time of the Timer
         * @details Returns 0 if the Timer is currently running or hasnt been started
         *
         * @fn getStopTime() const
         * @return unsigned long
        */
        virtual unsigned long getStopTime() const;

        /**
         * @brief Get the Difference between start and stop time
         * @details Returns 0 if start and stop time are equal. Also if the Timer is running or hasnt been started,
         * 0 will be returned
         *
         * @fn getDifference() const
         * @return unsigned long
        */
        virtual unsigned long getDifference() const;

        /**
         * @brief Get the current state of the Timer
         * @details See @ref AbstractTimer::TimerState for details
         *
         * @fn getState() const
         * @return TimerState
        */
        virtual TimerState getState() const;

        /**
         * @brief Get the current time out of the Timer
         * @details This will use the OS native Timer with highest precision
         *
         * @fn getCurrentTime() const
         * @return unsigned long
        */
        virtual unsigned long getCurrentTime() const = 0;

    signals:
        /**
         * @brief Signals that the Timer has been started
         * @details m_startTime will be emitted
         *
         * @fn started(unsigned long) (signal)
         * @param startTime
        */
        void started(unsigned long startTime);

        /**
         * @brief Signals that the Timer has been stopped
         * @details m_difference will be emitted
         *
         * @see AbstractTimer::stopped(unsigned long, unsigned long)
         *
         * @fn stopped(unsigned long) (signal)
         * @param difference
        */
        void stopped(unsigned long difference);

        /**
         * @brief Signals that the Timer has been stopped
         * @details m_stopTime and m_startTime will be emitted
         *
         * @fn stopped(unsigned long, unsigned long) (signal)
         * @param stopTime
         * @param startTime
        */
        void stopped(unsigned long stopTime, unsigned long startTime);

    public slots:
        /**
         * @brief Start the Timer
         * @details Will set m_startTime to the current time. The highest possible resolution will be used
         *
         * @fn start()
        */
        virtual void start() = 0;

        /**
         * @brief Stops the Timer
         * @details Will set m_stopTimer to the current time. Also the difference will be calculated
         *
         * @fn stop()
        */
        virtual void stop() = 0;

        /**
         * @brief Reset the Timer
         * @details Clear start and stop time and reset the internal state to NONE
         *
         * @fn reset()
        */
        void reset();

    protected:
        /**
         * @brief Set the internal state of the Timer
         *
         * @fn setState(TimerState)
         * @param state
        */
        void setState(TimerState state);

        /**
         * @var m_startTime
         * @details Representing the time when the Timer was started or created
        */
        unsigned long m_startTime;

        /**
         * @var m_stopTime
         * @details Representing the time when the Timer was stopped
        */
        unsigned long m_stopTime;

    private:
        /**
         * @var m_state
         * @details The internal state of the Timer
         * @see AbstractTimer::TimerState
        */
        TimerState m_state;
    };

} // End of Namespace Timer

#endif // ABSTRACTTIMER_HPP
